
package com.dhcc.core.framework.beetl.resource;

import java.io.File;
import java.net.URL;
import java.util.LinkedList;
import java.util.Map;

import org.beetl.core.GroupTemplate;
import org.beetl.core.Resource;
import org.beetl.core.ResourceLoader;
import org.beetl.core.misc.BeetlUtil;

/*
 * 自定义beetl资源加载器
 * @Description: 目的是实现在sys-home找不到资源时再从classpath下找
 * @Version: 4.0
 * @Autor: cyf
 * @Date: 2019-05-29 15:04:22
 * @LastEditors: cyf
 * @LastEditTime: 2020-02-22 17:57:43
 */
public class BeetlResourceLoader implements ResourceLoader {
    private String sysHomePath = null;
    private String viewPath = null;
    private String rootPath = null;
    private String charset = "UTF-8";
    boolean autoCheck = false;
    private String functionRoot = "funtion";
    private String functionSuffix = "fn";
    private GroupTemplate gt = null;
    private ClassLoader classLoader = null;

    public BeetlResourceLoader(String sysHomePath, String viewPath) {
        classLoader = this.getClass().getClassLoader();
        this.sysHomePath = sysHomePath;
        this.viewPath = checkViewPath(viewPath);
        this.rootPath = sysHomePath + viewPath + File.separator;
    }

    public BeetlResourceLoader(String sysHomePath, String viewPath, String charset) {
        classLoader = this.getClass().getClassLoader();
        this.sysHomePath = sysHomePath;
        this.viewPath = checkViewPath(viewPath);
        this.rootPath = sysHomePath + viewPath + File.separator;
        this.charset = charset;
    }

    public BeetlResourceLoader(ClassLoader classLoader, String sysHomePath, String viewPath, String charset) {
        this.classLoader = classLoader;
        this.sysHomePath = sysHomePath;
        this.viewPath = checkViewPath(viewPath);
        this.rootPath = sysHomePath + viewPath + File.separator;
        this.charset = charset;
    }

    @Override
    public Resource getResource(String key) {
        if (new File(rootPath, key).exists()) {
            File file = new File(rootPath, key);
            Resource resource = new BeetlResource(file, key, this);
            resource.setResourceLoader(this);
            return resource;
        } else {
            Resource resource = new BeetlResource(key, this.getChildPath(viewPath, key), this);
            return resource;
        }
    }

    @Override
    public boolean isModified(Resource resource) {
        if (this.autoCheck) {
            BeetlResource br = (BeetlResource) resource;
            if (br.getIsClassLoader()) {
                if (new File(rootPath, br.getId()).exists()) {
                    return true;
                }
            } else {
                String path = this.getChildPath(viewPath, br.getId());
                URL url = this.classLoader.getResource(path);
                if (url == null) {
                    // 兼容以前的
                    url = this.classLoader.getClass().getResource(path);
                }
                if (url != null) {
                    return true;
                }
            }
            return resource.isModified();
        } else {
            return false;
        }
    }

    @Override
    public boolean exist(String key) {
        if (new File(rootPath, key).exists()) {
            return true;
        }
        String path = this.getChildPath(viewPath, key);
        URL url = this.classLoader.getResource(path);
        if (url == null) {
            // 兼容以前的
            url = this.classLoader.getClass().getResource(path);
        }
        return url != null;
    }

    @Override
    public void close() {

    }

    @Override
    public void init(GroupTemplate gt) {

        Map<String, String> resourceMap = gt.getConf().getResourceMap();
        if (resourceMap.get("root") != null) {

            String temp = resourceMap.get("root");
            File test = new File(rootPath, temp);
            this.rootPath = test.toString();
            temp = checkViewPath(temp);
            this.viewPath = this.getChildPath(viewPath, temp);
        }

        if (this.charset == null) {
            this.charset = resourceMap.get("charset");

        }

        this.functionSuffix = resourceMap.get("functionSuffix");
        this.autoCheck = Boolean.parseBoolean(resourceMap.get("autoCheck"));
        this.functionRoot = resourceMap.get("functionRoot");

    }

    @Override
    public String getResourceId(Resource resource, String id) {
        if (resource == null) {
            return id;
        } else {
            return BeetlUtil.getRelPath(resource.getId(), id);
        }
    }

    @Override
    public String getInfo() {
        return "BeetlResourceLoader:" + this.classLoader + " Path:" + viewPath;
    }

    protected String getChildPath(String path, String child) {
        // 首先, 与父路径拼接起来
        String re = null;
        if (child.length() == 0) {
            return path;
        } else if (child.startsWith("/")) {
            re = path + child;
        } else {
            re = path + "/" + child;
        }
        // 如果不包含`../` 或者 `./`,那就无需处理了
        if (!re.contains("./")) {
            return re;
        }
        // 分解成一段一段的路径 此处，要么按照这样修改  要么修改template模板文件的路径到相同include页面的相同路径下
        String[] tmp = re.split("[\\\\/]");
        LinkedList<String> list = new LinkedList<String>();
        for (String str : tmp) {
            if (str == null || str.isEmpty()) {
                continue;
            }
            // 向上退一层 去掉一段路径
            if ("..".equals(str)) {
                int sz = list.size();
                // 预防顶部异常
                if (sz > 0)
                {
                    list.remove(sz - 1);
                }
                // 属于多余路径,跳过
            } else if (".".equals(str))
            {
                continue;
            } else {
                list.add(str);
            }
        }
        // 没有一个值? 返回空, 或者抛异常?
        if (list.isEmpty()) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        for (String str : list) {
            sb.append(str).append('/');
        }
        sb.setLength(sb.length() - 1);
        return sb.toString();
    }

    /**
     * 检查classpath路径
     * 
     * @param path
     * @return
     */
    protected String checkViewPath(String path) {
        if (path == null || path.length() == 0 || "/".equals(path)) {
            return "";

        } else if (path.endsWith("/")) {
            return path.substring(0, path.length() - 1);
        } else if (path.startsWith("/")) {
            return path.substring(1, path.length());
        } else {
            return path;
        }
    }

    /**
     * @return String return the sysHomePath
     */
    public String getSysHomePath() {
        return sysHomePath;
    }

    /**
     * @param sysHomePath the sysHomePath to set
     */
    public void setSysHomePath(String sysHomePath) {
        this.sysHomePath = sysHomePath;
    }

    /**
     * @return String return the viewPath
     */
    public String getViewPath() {
        return viewPath;
    }

    /**
     * @param viewPath the viewPath to set
     */
    public void setViewPath(String viewPath) {
        this.viewPath = viewPath;
    }

    /**
     * @return String return the rootPath
     */
    public String getRootPath() {
        return rootPath;
    }

    /**
     * @param rootPath the rootPath to set
     */
    public void setRootPath(String rootPath) {
        this.rootPath = rootPath;
    }

    /**
     * @return String return the charset
     */
    public String getCharset() {
        return charset;
    }

    /**
     * @param charset the charset to set
     */
    public void setCharset(String charset) {
        this.charset = charset;
    }

    /**
     * @return String return the functionRoot
     */
    public String getFunctionRoot() {
        return functionRoot;
    }

    /**
     * @param functionRoot the functionRoot to set
     */
    public void setFunctionRoot(String functionRoot) {
        this.functionRoot = functionRoot;
    }

    /**
     * @return String return the functionSuffix
     */
    public String getFunctionSuffix() {
        return functionSuffix;
    }

    /**
     * @param functionSuffix the functionSuffix to set
     */
    public void setFunctionSuffix(String functionSuffix) {
        this.functionSuffix = functionSuffix;
    }

    /**
     * @return GroupTemplate return the gt
     */
    public GroupTemplate getGt() {
        return gt;
    }

    /**
     * @param gt the gt to set
     */
    public void setGt(GroupTemplate gt) {
        this.gt = gt;
    }

    /**
     * @param classLoader the classLoader to set
     */
    public void setClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    public ClassLoader getClassLoader() {
        return classLoader;
    }
}